package org.alesv.common.webapp.session;

import java.util.HashMap;
import java.util.Iterator;

import org.alesv.common.utils.UtilDefaultProperties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Objeto que se guardará en sesión. <br>
 * Será el único objeto que tendrá la sesión y lo que se incrementarán serán sus
 * atributos, <a href="SessionAttribute.html">SessionAttribute</a>, hasta un
 * determinado valor.
 * 
 * @see <a href="SessionManager.html">SessionManager</a>, <a
 *      href="SessionAttribute.html">SessionAttribute</a>
 */
public class SessionObject {

	/**
	 * Atributos.
	 */
	private HashMap<String, SessionAttribute> attributes;

	/**
	 * Numero máximo de atributos.
	 */
	private static int maxNumAttributes;

	/**
	 * Para escribir trazas.
	 */
	private transient static final Log log = LogFactory
			.getLog(SessionObject.class);

	static {
		try {
			maxNumAttributes = Integer.parseInt(UtilDefaultProperties
					.getNumObjectSession());
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
	}

	/**
	 * Constructor.<br>
	 * Establece el número de atributos de este objeto marcado por la propiedad
	 * <i>org.alesv.common.webapp.session.size</i> el fichero
	 * <i>ingfwproperties.properties</i> de configuración.
	 */
	public SessionObject() {
		attributes = new HashMap<String, SessionAttribute>(maxNumAttributes);
	}

	/**
	 * Método que devuelve el identificador del elemento más antiguo de la lista
	 * de atributos cuando dicha lista alcanzó el número máximo que se
	 * especifica en el fichero de configuración.<br>
	 * 
	 * @return <code>String</code>, identificador del elementos más antiguo o
	 *         <b>null</b> si el tamaño de la lista de atributos aún puede
	 *         almacenar más.
	 */
	private String getAttributeNameToRemove() {
		long older = Long.MAX_VALUE;
		String key = null;
		SessionAttribute value = null;
		String result = null;

		// Si el número de atributos coincide con el máximo especificado.
		if (attributes.size() == maxNumAttributes) {
			Iterator<String> i = attributes.keySet().iterator();
			while (i.hasNext()) {
				key = i.next();
				value = attributes.get(key);
				if (value.getTimeStamp() < older) {
					older = value.getTimeStamp();
					result = key;
				}
			}
		}

		return result;
	}

	/**
	 * Establece el atributo con el nombre y el valor introducidos.<br>
	 * 
	 * @param name
	 *            nombre del atributo (key)
	 * @param o
	 *            valor del atributo
	 */
	public void setAttribute(String name, Object o) {
		SessionAttribute attribute = attributes.get(name);
		if (attribute != null) {
			attribute.setTimeStamp(System.currentTimeMillis());
			attribute.setValue(o);
		} else {
			attributes.remove(getAttributeNameToRemove());
			attribute = new SessionAttribute();
			attribute.setTimeStamp(System.currentTimeMillis());
			attribute.setValue(o);
			attributes.put(name, attribute);
		}
	}

	/**
	 * Obtiene el objeto a partir de su nombre <param>name</param><br>
	 * 
	 * @param name
	 *            nombre del objeto que se quiere obtener
	 * @return <code>Object</code> objeto requerido o <b>null</b> si éste no
	 *         existe.
	 */
	public Object getAttribute(String name) {
		SessionAttribute attribute = attributes.get(name);
		return attribute == null ? null : attribute.getValue();
	}

	/**
	 * Elimina el objeto de acuerdo al nombre introducido. <br>
	 * 
	 * @param name
	 *            nombre del objeto a eliminar.
	 */
	public void removeAttribute(String name) {
		attributes.remove(name);
	}

	/**
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		StringBuffer sb = new StringBuffer();
		String key = null;
		Iterator<String> i = attributes.keySet().iterator();
		while (i.hasNext()) {
			key = i.next();
			sb.append("[").append(key).append(" -> ").append(getAttribute(key))
					.append("]<br>");
		}
		return sb.toString();
	}

}
